using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using FarseerPhysics.Common.ConvexHull;
using FarseerPhysics.Common;


namespace FoodWar.Episode1.Components
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class RagDoll : Microsoft.Xna.Framework.DrawableGameComponent
    {
        public GameFITClub game;
        public Model SourceModel;
        public List<Vector3> SourceVertices;
        public Vertices InputVertices, OutputVertices2;
        public VertexPositionColor[] OutputVertices3C;
        public Vector3 pos = Vector3.Zero;
        public float rx = 0, ry = 0, rz = 0;

        public RagDoll(GameFITClub game)
            : base(game)
        {
            this.game = game;
            SourceVertices = new List<Vector3>();
            InputVertices = new Vertices();                        
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        public static Matrix GetAbsoluteTransform(ModelBone bone)
        {
            if (bone == null)
                return Matrix.Identity;
            return bone.Transform * GetAbsoluteTransform(bone.Parent);
        }

        /// <summary>
        /// Loads any component specific content
        /// </summary>
        protected override void LoadContent()
        {
            // TODO: Load any content
            SourceModel = game.Content.Load<Model>("character");
            foreach (ModelMesh mesh in SourceModel.Meshes)
            {
                Console.WriteLine("new mesh: " + mesh.Name + " parent bone index = " + mesh.ParentBone.Index);
            }
            Model m = game.Content.Load<Model>("character");
            foreach (ModelMesh mm in m.Meshes)
            {
                if (mm.Name == "Boundry_ruka_L")
                {
                    foreach (ModelMeshPart mmp in mm.MeshParts)
                    {
                        Console.WriteLine("mesh part" + mmp.NumVertices + ","+ mmp.PrimitiveCount+","+mmp.StartIndex+","+mmp.VertexOffset+","+mmp.VertexBuffer.VertexCount+","+mmp.VertexBuffer.VertexDeclaration.VertexStride+",");
                        // The stride is how big, in bytes, one vertex is in the vertex buffer
                        // We have to use this as we do not know the make up of the vertex
                        int stride = mmp.VertexBuffer.VertexDeclaration.VertexStride;

                        byte[] vertexData = new byte[stride * mmp.NumVertices];
                        mmp.VertexBuffer.GetData<byte>(vertexData);
                        //mmp.VertexBuffer.GetData(mmp.VertexOffset * stride, vertexData, 0, mmp.NumVertices, 1); // fixed 13/4/11
                        foreach (byte item in vertexData)
                        {
                            Console.Write(string.Format("{0:x} ", item));
                        }
                        Vector3[] a = new Vector3[mmp.NumVertices];
                        int ndx = 0;
                        for (int i = 0; i < a.Length; i++)
                        {
                            a[i].X = BitConverter.ToSingle(vertexData, ndx);
                            a[i].Y = BitConverter.ToSingle(vertexData, ndx + sizeof(float));
                            a[i].Z = BitConverter.ToSingle(vertexData, ndx + sizeof(float) * 2);
                            ndx += stride;
                        }
                        //mmp.VertexBuffer.GetData<Vector3>(a);
                        //for (int i = 0; i < a.Length; i++)
                        //{
                        //    a[i] = Vector3.Transform(a[i], (mm.ParentBone.Transform));
                        //}
                        SourceVertices.AddRange(a);
                    }
                }
            }
            foreach (Vector3 v in SourceVertices)
            {
                Console.WriteLine(v);
                InputVertices.Add(new Vector2(v.X, v.Y));
            }
            Console.WriteLine("count = " + SourceVertices.Count);
            OutputVertices2 = ChainHull.GetConvexHull(InputVertices);//GiftWrap.GetConvexHull(InputVertices);
            OutputVertices3C = new VertexPositionColor[OutputVertices2.Count + 1];
            for (int i = 0; i < OutputVertices2.Count; i++)
            {
                OutputVertices3C[i] = new VertexPositionColor(new Vector3(OutputVertices2[i],0),Color.Red);
            }
            OutputVertices3C[OutputVertices2.Count] = OutputVertices3C[0];

            base.LoadContent();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here
            KeyboardState keyboard = Keyboard.GetState();
            if (keyboard.IsKeyDown(Keys.A))
            {
                pos.X -= 0.1f;
            }
            if (keyboard.IsKeyDown(Keys.D))
            {
                pos.X += 0.1f;
            }
            if (keyboard.IsKeyDown(Keys.S))
            {
                pos.Y -= 0.1f;
            }
            if (keyboard.IsKeyDown(Keys.W))
            {
                pos.Y += 0.1f;
            }
            if (keyboard.IsKeyDown(Keys.R))
            {
                rx -= 1;
            }
            if (keyboard.IsKeyDown(Keys.T))
            {
                rx += 1;
            }
            if (keyboard.IsKeyDown(Keys.F))
            {
                ry -= 1;
            }
            if (keyboard.IsKeyDown(Keys.G))
            {
                ry += 1;
            }
            if (keyboard.IsKeyDown(Keys.V))
            {
                rz -= 1;
            }
            if (keyboard.IsKeyDown(Keys.B))
            {
                rz += 1;
            }

            base.Update(gameTime);
        }

        /// <summary>
        /// Allows the game component to draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Draw(GameTime gameTime)
        {
            // TODO: Add your drawing code here
            foreach (ModelMesh mesh in SourceModel.Meshes)
            {
                if (mesh.Name.StartsWith("Boundry"))
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        //effect.Alpha = .5f;
                        //effect.TextureEnabled = false;
                        effect.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
                        effect.EnableDefaultLighting();
                        effect.PreferPerPixelLighting = true;
                        effect.World = Matrix.CreateRotationX(MathHelper.ToRadians(rx)) * Matrix.CreateRotationY(MathHelper.ToRadians(ry)) * Matrix.CreateRotationZ(MathHelper.ToRadians(rz)) * Matrix.CreateTranslation(pos);
                        effect.View = game.ViewMatrix;
                        effect.Projection = game.ProjectionMatrix;
                    }
                    mesh.Draw();
                }
            }
            BasicEffect e = new BasicEffect(GraphicsDevice);
            e.VertexColorEnabled = true;
            e.Projection = game.ProjectionMatrix;
            e.View = game.ViewMatrix;
            e.CurrentTechnique.Passes[0].Apply(); 
            GraphicsDevice.SamplerStates[0] = SamplerState.AnisotropicClamp;
            GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineStrip, OutputVertices3C, 0, OutputVertices3C.Length-1);
            e.Dispose();
            base.Draw(gameTime);
        }
    }
}
